package com.clickpaas.workinghours.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.clickpaas.workinghours.config.AutoLoadConfig;
import com.clickpaas.workinghours.entity.MainDataRep;
import com.clickpaas.workinghours.entity.TimeCardDateEntity;
import com.clickpaas.workinghours.entity.TimeCardEntity;
import com.clickpaas.workinghours.thread.CastListCopyCallable;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.json.JSONArray;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

@Slf4j
public class DataInfoUtil {

    /**
     * 判空转换为默认值
     * @param tagert 目标值
     * @param defaltValue 默认值
     * @return
     */
    public static String setDefaltValue(String tagert,String defaltValue){
        if(StringUtils.isBlank(tagert)){
            return defaltValue;
        }
        return tagert;
    }

    /**
     * string时间转整型
     * @param date
     * @return
     * @throws ParseException
     */
    private static Long stringDate2Int(String date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date dateTime= null;
        try {
            dateTime = format.parse(date);
        } catch (ParseException e) {
            log.info("时间转换失败：【{}】",e);
        }
        long timeLong =dateTime.getTime();
        return timeLong;
    }

    /**
     * 对象属性判空
     * @param obj
     * @return
     * @throws Exception
     */
    public static boolean isAllFieldNull(Object obj) throws Exception{
        Class stuCla = (Class) obj.getClass();// 得到类对象
        Field[] fs = stuCla.getDeclaredFields();//得到属性集合
        boolean flag = true;
        for (Field f : fs) {
            /**
             * 设置属性是可以访问的(私有的也可以)
             */
            f.setAccessible(true);
            /**
             * 得到此属性的值
             */
            Object val = f.get(obj);
            /**
             * 只要有1个属性不为空,那么就不是所有的属性值都为空
             */
            if(val!=null && StringUtils.isNotBlank(val.toString())) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    /**
     * 对象降序排列
     */
    public static void sortTimeCardDate(List<TimeCardDateEntity> entities){
        Collections.sort(entities, new Comparator<TimeCardDateEntity>() {

            @Override
            public int compare(TimeCardDateEntity entity1, TimeCardDateEntity entity2) {
                int i = DataInfoUtil.stringDate2Int(entity1.getTimeCardDate()).intValue() - DataInfoUtil.stringDate2Int(entity2.getTimeCardDate()).intValue();
                if(i == 0){
                    return -1;
                }
                return i;
            }
        });
    }

    /**
     * 对象降序排列
     */
    public static void sortTimeCard(List<TimeCardEntity> entities){
        Collections.sort(entities, new Comparator<TimeCardEntity>() {

            @Override
            public int compare(TimeCardEntity entity1, TimeCardEntity entity2) {
                int i = Integer.valueOf(entity1.getId().substring(1)) - Integer.valueOf(entity2.getId().substring(1));
                if(i == 0){
                    return -1;
                }
                return i;
            }
        });
    }


    // 获得当前周- 周一的日期
    public static String getCurrentMonday(String date) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Calendar cal = stringFormat2Date(date);
        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        if(1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek()-day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        return sdf.format(cal.getTime());
    }

    // 获得当前周- 周日  的日期
    public static String  getPreviousSunday(String date) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Calendar cal = stringFormat2Date(date);
        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        if(1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }

        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一

        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek()-day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, 6);
        return sdf.format(cal.getTime());
    }

    /**
     * string格式化时间对象
     * @param date
     * @return
     */
    public static Calendar stringFormat2Date(String date){
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式
        Calendar cal = Calendar.getInstance();
        Date time= null;
        try {
            if (StringUtils.isBlank(date)){
                time = new Date();
            }else {
                time = sdf.parse(date);
            }
        } catch (ParseException e) {
            log.info("日期【{}】转换失败",date);
        }
        cal.setTime(time);
        return cal;
    }

    /**
     * 计算明天的日期
     * @param date
     * @return
     */
    public static String dateAfter(String date){
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        //取今天日期,如果日期类型为String类型,可以使用df.parse()方法,转换为Date类型
        Calendar calendar = Calendar.getInstance();//new一个Calendar类,把Date放进去
        Date parse = null;
        try {
            parse = df.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        calendar.setTime(parse);
        calendar.add(Calendar.DATE, 1);//实现日期加一操作,也就是明天
        return df.format(calendar.getTime());
    }

    /**
     * 对象转数组
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if(obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    /**
     * 对象转数组
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> castGjsontoList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        Gson gson = new Gson();
        if(obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                String jsonString = JSON.toJSONString(o);
                T t = gson.fromJson(jsonString, clazz);
                result.add(t);
            }
            return result;
        }
        return null;
    }

    /**
     * 获取主数据
     * @param mainDataList
     * @param tableName 对象名
     * @return
     */
    public static Map<Object, Object> getMainData(HashMap mainDataList,String tableName,String token) {
        Map<Object, Object> resMap = Maps.newConcurrentMap();
        CountDownLatch countDownLatch = new CountDownLatch(mainDataList.size());
        ThreadPoolExecutor threadPoolExecutor = threadPoolExecutor();
        try {
            mainDataList.forEach((k, v) -> {
                threadPoolExecutor.execute(() -> {
                    List<String> sourceData = getSourceData(tableName+"." + v,token);
                    MainDataRep mainData = new MainDataRep(k, sourceData);
                    resMap.put(v, mainData);
                    countDownLatch.countDown();
                });
            });
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPoolExecutor.shutdown();
        }
        return resMap;
    }

    /**
     * 请求数据
     * @param pojoAndfield
     * @return
     */
    private static List<String> getSourceData(String pojoAndfield,String token) {
        List<String> res = new ArrayList<>();

        String region = "cn-north-2";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String sign = DigestUtils.md5Hex(AutoLoadConfig.ACCESSKEY_ID + AutoLoadConfig.ACCESSKEY_SECRET + timestamp);

        JSONObject body = new JSONObject();
        body.put("data", pojoAndfield);

        Unirest.setTimeouts(5000000, 5000000);
        try {
            HttpResponse<JsonNode> response;
            if(StringUtils.isNotBlank(token)){
                //租户账号访问
                response = Unirest.post(AutoLoadConfig.MAIN_DATAS_URL)
                        .header("Content-Type", "application/json")
                        .header("accessKeyId", AutoLoadConfig.ACCESSKEY_ID)
                        .header("accessKeySecret", AutoLoadConfig.ACCESSKEY_SECRET)
                        .header("region", region)
                        .header("timestamp", timestamp)
                        .header("sign", sign)
                        .header("accessToken",token)
                        .body(body.toJSONString())
                        .asJson();
            }else {
                //Saas账号
                response = Unirest.post(AutoLoadConfig.MAIN_DATAS_URL)
                        .header("Content-Type", "application/json")
                        .header("accessKeyId", AutoLoadConfig.ACCESSKEY_ID)
                        .header("accessKeySecret", AutoLoadConfig.ACCESSKEY_SECRET)
                        .header("region", region)
                        .header("timestamp", timestamp)
                        .header("sign", sign)
                        .body(body.toJSONString())
                        .asJson();
            }
            if (HttpStatus.SC_OK == response.getStatus()) {
                org.json.JSONObject object = response.getBody().getObject();
                if (null == object
                        || !"SUCCESS".equals(object.getString("message"))
                        || null == object.getJSONArray("data")){
                    res.add(object.getString("message"));
                    return res;
                }
                JSONArray data = object.getJSONArray("data");
                if (data != null && data.length() > 0) {
                    data.forEach(item -> {
                        JSONObject itemJson = JsonUtil.objToJson(item);
                        if (itemJson != null) {
                            res.add(itemJson.getString("name"));
                        }
                    });
                }
            }
        } catch (UnirestException e) {
            log.info("主数据查询异常：【{}】",e);
            return new ArrayList<>();
        }
        return res;
    }

    public static ThreadPoolExecutor threadPoolExecutor() {
        return new ThreadPoolExecutor(
                5
                , 5
                , 5L
                , TimeUnit.MINUTES
                , new LinkedBlockingQueue<>()
                , Executors.defaultThreadFactory()
                , new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }

    /**
     * @company <上海爱湃斯科技有限公司>
     * @email <zhihui.peng@clickpaas.com>
     * @author huiye
     * @decription: 对象复制
     * @date 2021/2/1 2:13 下午
     */
    public static <T> List<T> castListCopy(Object obj, Class<?> clazz, Class<T> reClazz) {
        if (null == obj || !(obj instanceof List<?>))return null;
        List listsize = (List<?>)obj;
        ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        ArrayList<Future<T>> futures = new ArrayList<>();
        ArrayList<T> returnCodeList = new ArrayList<>();

        try {
            for (int i = 0; i < listsize.size(); i++) {
                CastListCopyCallable castListCopyCallable = new CastListCopyCallable(listsize.get(i), clazz, reClazz);
                Future<T> submit = pool.submit(castListCopyCallable);
                futures.add(submit);
            }
        }catch (Exception e){
            log.info("对象复制线程报错：【{}】",e);
        }finally {
            pool.shutdown();
        }

        for (Future<T> f : futures) {
            try {
                T t = f.get();
                returnCodeList.add((T)t);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (returnCodeList.size()>0){
            return returnCodeList;
        }
        return null;
    }

    /**
     * 当前时间
     * @return
     */
    public static String getNowDay() {
        SimpleDateFormat sdf =   new SimpleDateFormat( "yyyy-MM-dd" );
        return sdf.format(new Date());
    }
}
